package com.example.demo.utils;

import cn.hutool.core.util.StrUtil;
import com.example.demo.bean.SysJob;
import com.example.demo.util.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;

/**
 * 任务执行工具
 */
@Slf4j
public class JobInvokeUtil
{
    /**
     * 执行方法
     *
     * @param sysJob 系统任务
     */
    public static void invokeMethod(SysJob sysJob) throws Exception
    {
        String invokeTarget = sysJob.getInvokeTarget();
        if (StringUtils.isEmpty(invokeTarget)) {
            throw new IllegalArgumentException("任务调用目标字符串不能为空");
        }
        
        String beanName = getBeanName(invokeTarget);
        String methodName = getMethodName(invokeTarget);
        List<Object[]> methodParams = getMethodParams(invokeTarget);

        log.info("执行任务：beanName={}, methodName={}, params={}", beanName, methodName, methodParams);

        if (isValidClassName(beanName))
        {
            try {
                Object bean = Class.forName(beanName).getDeclaredConstructor().newInstance();
                invokeMethod(bean, methodName, methodParams);
            } catch (ClassNotFoundException e) {
                log.error("找不到类：{}", beanName, e);
                throw new RuntimeException("找不到类：" + beanName, e);
            } catch (Exception e) {
                log.error("实例化类失败：{}", beanName, e);
                throw new RuntimeException("实例化类失败：" + beanName, e);
            }
        }
        else
        {
            try {
                Object bean = SpringUtils.getBean(beanName);
                if (bean == null) {
                    throw new RuntimeException("找不到Spring Bean：" + beanName);
                }
                invokeMethod(bean, methodName, methodParams);
            } catch (Exception e) {
                log.error("获取Spring Bean失败：{}", beanName, e);
                throw new RuntimeException("获取Spring Bean失败：" + beanName, e);
            }
        }
    }

    /**
     * 调用任务方法
     *
     * @param bean 目标对象
     * @param methodName 方法名称
     * @param methodParams 方法参数
     */
    private static void invokeMethod(Object bean, String methodName, List<Object[]> methodParams)
            throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
            InvocationTargetException
    {
        if (StringUtils.isEmpty(methodName)) {
            throw new IllegalArgumentException("方法名不能为空");
        }
        
        try {
            if (methodParams != null && methodParams.size() > 0)
            {
                Method method = bean.getClass().getMethod(methodName, getMethodParamsType(methodParams));
                method.invoke(bean, getMethodParamsValue(methodParams));
            }
            else
            {
                Method method = bean.getClass().getMethod(methodName);
                method.invoke(bean);
            }
            log.info("任务方法执行成功：{}.{}", bean.getClass().getSimpleName(), methodName);
        } catch (NoSuchMethodException e) {
            log.error("找不到方法：{}.{}", bean.getClass().getName(), methodName, e);
            throw e;
        } catch (InvocationTargetException e) {
            log.error("方法执行异常：{}.{}", bean.getClass().getName(), methodName, e);
            throw e;
        } catch (Exception e) {
            log.error("方法调用异常：{}.{}", bean.getClass().getName(), methodName, e);
            throw e;
        }
    }

    /**
     * 校验是否为为class包名
     * 
     * @param invokeTarget 名称
     * @return true是 false否
     */
    public static boolean isValidClassName(String invokeTarget)
    {
        return StringUtils.countMatches(invokeTarget, ".") > 1;
    }

    /**
     * 获取bean名称
     * 
     * @param invokeTarget 目标字符串
     * @return bean名称
     */
    public static String getBeanName(String invokeTarget)
    {
        String beanName = StringUtils.substringBefore(invokeTarget, "(");
        String extractedName = StringUtils.substringBeforeLast(beanName, ".");
        
        // 如果是接口名称，尝试找到对应的实现类
        if (extractedName.startsWith("I") && extractedName.endsWith("Service")) {
            // 将接口名转换为实现类名
            String implName = extractedName.substring(1) + "Impl";
            // 尝试从Spring容器获取实现类Bean
            try {
                Object bean = SpringUtils.getBean(implName);
                if (bean != null) {
                    return implName;
                }
            } catch (Exception e) {
                log.warn("无法找到接口 {} 对应的实现类 {}", extractedName, implName);
            }
        }
        
        return extractedName;
    }

    /**
     * 获取bean方法
     * 
     * @param invokeTarget 目标字符串
     * @return method方法
     */
    public static String getMethodName(String invokeTarget)
    {
        String methodName = StringUtils.substringBefore(invokeTarget, "(");
        return StringUtils.substringAfterLast(methodName, ".");
    }

    /**
     * 获取method方法参数相关列表
     * 
     * @param invokeTarget 目标字符串
     * @return method方法相关参数列表
     */
    public static List<Object[]> getMethodParams(String invokeTarget)
    {
        String methodStr = StringUtils.substringBetween(invokeTarget, "(", ")");
        if (StringUtils.isEmpty(methodStr))
        {
            return null;
        }
        String[] methodParams = methodStr.split(",(?=([^\"']*[\"'][^\"']*[\"'])*[^\"']*$)");
        List<Object[]> classs = new LinkedList<>();
        for (int i = 0; i < methodParams.length; i++)
        {
            String str = StringUtils.trimToEmpty(methodParams[i]);
            if (StringUtils.isEmpty(str)) {
                continue; // 跳过空参数
            }
            
            // String字符串类型，以'或"开头
            if (StringUtils.startsWithAny(str, "'", "\""))
            {
                String value = StringUtils.substring(str, 1, str.length() - 1);
                if (StringUtils.isNotEmpty(value)) {
                    classs.add(new Object[] { value, String.class });
                }
            }
            // boolean布尔类型，等于true或者false
            else if ("true".equalsIgnoreCase(str) || "false".equalsIgnoreCase(str))
            {
                classs.add(new Object[] { Boolean.valueOf(str), Boolean.class });
            }
            // long长整形，以L结尾
            else if (StringUtils.endsWith(str, "L"))
            {
                try {
                    classs.add(new Object[] { Long.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Long.class });
                } catch (NumberFormatException e) {
                    log.warn("无法解析长整型参数：{}，将作为字符串处理", str);
                    classs.add(new Object[] { str, String.class });
                }
            }
            // double浮点类型，以D结尾
            else if (StringUtils.endsWith(str, "D"))
            {
                try {
                    classs.add(new Object[] { Double.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Double.class });
                } catch (NumberFormatException e) {
                    log.warn("无法解析浮点型参数：{}，将作为字符串处理", str);
                    classs.add(new Object[] { str, String.class });
                }
            }
            // 其他类型归类为整形
            else
            {
                try {
                    classs.add(new Object[] { Integer.valueOf(str), Integer.class });
                } catch (NumberFormatException e) {
                    log.warn("无法解析参数为整数：{}，将作为字符串处理", str);
                    classs.add(new Object[] { str, String.class });
                }
            }
        }
        return classs;
    }

    /**
     * 获取参数类型
     * 
     * @param methodParams 参数相关列表
     * @return 参数类型列表
     */
    public static Class<?>[] getMethodParamsType(List<Object[]> methodParams)
    {
        if (methodParams == null || methodParams.isEmpty()) {
            return new Class[0];
        }
        Class<?>[] classs = new Class<?>[methodParams.size()];
        int index = 0;
        for (Object[] os : methodParams)
        {
            classs[index] = (Class<?>) os[1];
            index++;
        }
        return classs;
    }

    /**
     * 获取参数值
     * 
     * @param methodParams 参数相关列表
     * @return 参数值列表
     */
    public static Object[] getMethodParamsValue(List<Object[]> methodParams)
    {
        if (methodParams == null || methodParams.isEmpty()) {
            return new Object[0];
        }
        Object[] classs = new Object[methodParams.size()];
        int index = 0;
        for (Object[] os : methodParams)
        {
            classs[index] = (Object) os[0];
            index++;
        }
        return classs;
    }
}
